"""
主话术管理器，用于从配置路径获取主话术
"""
import os
import random
from typing import List, Optional
from app.utils.logger import Logger
from app.services.service_locator import ServiceLocator
from app.services.config_service import IConfigService


class MainSpeechManager:
    """
    主话术管理器，负责从配置路径获取主话术
    """
    
    def __init__(self, config_path: str):
        """
        初始化主话术管理器
        
        @param config_path: 配置路径
        """
        self.config_path = config_path
        
        # 获取日志记录器
        self.logger = Logger.get_logger("main_speech_manager")
        
        # 获取配置服务
        self.config_service = ServiceLocator.get(IConfigService)
        
        # 主话术缓存，键为文件名，值为文件内容
        self._main_speeches: dict = {}
        
        # 获取话术来源
        self.speech_source = "主话术"  # 默认使用主话术目录
        if self.config_service:
            self.speech_source = self.config_service.get("app.speech_source", "主话术")
        
        # 构建话术目录路径
        self.main_speech_dir = os.path.join(config_path, "话术管理", self.speech_source)
        
        self.logger.info(f"主话术管理器初始化，配置路径: {config_path}")
        self.logger.info(f"话术来源: {self.speech_source}")
        self.logger.info(f"话术目录: {self.main_speech_dir}")
        
        # 加载主话术
        self._load_main_speeches()
        
        self.logger.info(f"主话术管理器初始化完成，已加载 {len(self._main_speeches)} 个主话术文件")
    
    def set_speech_source(self, source: str) -> None:
        """
        设置话术来源
        
        @param source: 话术来源目录名
        """
        if not source:
            return
            
        self.speech_source = source
        self.main_speech_dir = os.path.join(self.config_path, "话术管理", source)
        self.logger.info(f"切换话术来源: {source}")
        self.logger.info(f"新的话术目录: {self.main_speech_dir}")
        
        # 重新加载话术
        self._load_main_speeches()
    
    def _load_main_speeches(self) -> None:
        """
        加载主话术
        """
        try:
            # 检查主话术目录是否存在
            if not os.path.exists(self.main_speech_dir):
                os.makedirs(self.main_speech_dir, exist_ok=True)
                self.logger.warning(f"主话术目录不存在，已创建: {self.main_speech_dir}")
                return
            
            self.logger.info(f"开始加载主话术，目录: {self.main_speech_dir}")
            
            # 清空缓存
            self._main_speeches.clear()
            
            # 获取主话术目录中的所有txt文件
            files = [f for f in os.listdir(self.main_speech_dir) 
                    if os.path.isfile(os.path.join(self.main_speech_dir, f)) 
                    and f.lower().endswith('.txt')]
            
            # 定义排序键函数，支持多种文件名格式
            def get_sort_key(filename):
                """
                从文件名中提取排序键
                支持以下格式：
                1. 破折号格式：01-产品名称.txt
                2. 纯数字格式：1.0.txt
                3. 带花括号的格式：3.0{停顿}.txt
                4. 带后缀的格式：6.1人数时间.txt
                """
                try:
                    # 先尝试破折号格式（如01-产品名称.txt）
                    import re
                    dash_match = re.match(r'^(\d+)-', filename)
                    if dash_match:
                        return int(dash_match.group(1))
                    
                    # 尝试x.y格式（如1.0.txt, 3.0{停顿}.txt）
                    dot_match = re.match(r'^(\d+\.\d+)', filename)
                    if dot_match:
                        return float(dot_match.group(1))
                    
                    # 尝试纯数字格式（如1.txt, 2.txt）
                    num_match = re.match(r'^(\d+)\.', filename)
                    if num_match:
                        return int(num_match.group(1))
                except (ValueError, IndexError, AttributeError) as e:
                    self.logger.warning(f"解析文件名'{filename}'的排序键时出错: {str(e)}")
                    
                # 如果无法提取排序键，则返回一个很大的数，使其排在最后
                self.logger.debug(f"文件'{filename}'无法提取排序键，将排在最后")
                return float('inf')
            
            # 按照排序键排序
            sorted_files = sorted(files, key=get_sort_key)
            
            # 添加调试日志
            self.logger.debug(f"排序后的文件列表: {sorted_files}")
            
            # 遍历排序后的文件
            file_count = len(sorted_files)
            for file_name in sorted_files:
                file_path = os.path.join(self.main_speech_dir, file_name)
                
                self.logger.debug(f"发现txt文件: {file_name}")
                
                try:
                    # 读取文件内容
                    with open(file_path, "r", encoding="utf-8") as f:
                        content = f.read().strip()
                        
                        # 如果内容不为空，添加到缓存
                        if content:
                            self._main_speeches[file_name] = content
                            self.logger.debug(f"已加载主话术文件: {file_name}")
                        else:
                            self.logger.warning(f"文件内容为空: {file_path}")
                except Exception as e:
                    self.logger.error(f"读取文件失败: {file_path}, 错误: {str(e)}")
            
            self.logger.info(f"主话术加载完成，共扫描 {file_count} 个txt文件，加载 {len(self._main_speeches)} 个主话术文件")
        except Exception as e:
            self.logger.error(f"加载主话术失败: {str(e)}")
    
    def get_random_speech_file(self) -> tuple:
        """
        获取随机主话术文件
        
        @return: 元组 (文件名, 文件内容)，如果没有则返回 (None, None)
        """
        try:
            # 如果缓存为空，重新加载
            if not self._main_speeches:
                self.logger.warning("主话术缓存为空，尝试重新加载")
                self._load_main_speeches()
            
            # 如果仍然为空，返回默认话术
            if not self._main_speeches:
                default_speech = "欢迎来到直播间，我是主播，很高兴为大家服务！"
                self.logger.warning(f"主话术为空，返回默认话术: {default_speech}")
                return ("default.txt", default_speech)
            
            # 随机选择一个主话术文件
            file_name = random.choice(list(self._main_speeches.keys()))
            content = self._main_speeches[file_name]
            self.logger.info(f"获取随机主话术文件: {file_name}")
            return (file_name, content)
        except Exception as e:
            self.logger.error(f"获取随机主话术文件失败: {str(e)}")
            return (None, None)
    
    def get_random_speech(self) -> Optional[str]:
        """
        获取随机主话术
        
        @return: 随机主话术，如果没有则返回 None
        """
        try:
            # 获取随机主话术文件
            file_name, content = self.get_random_speech_file()
            
            if not content:
                return None
            
            # 将内容按行分割
            lines = [line.strip() for line in content.split('\n') if line.strip()]
            
            # 如果没有有效行，返回None
            if not lines:
                self.logger.warning(f"主话术文件 {file_name} 没有有效行")
                return None
            
            # 随机选择一行
            speech = random.choice(lines)
            self.logger.info(f"从文件 {file_name} 中随机选择一行: {speech[:20]}...")
            return speech
        except Exception as e:
            self.logger.error(f"获取随机主话术失败: {str(e)}")
            return None
    
    def get_speech_file_name(self, speech_content: str) -> Optional[str]:
        """
        根据话术内容获取对应的文件名
        
        @param speech_content: 话术内容
        @return: 文件名，如果没有找到则返回 None
        """
        try:
            # 遍历所有主话术文件
            for file_name, content in self._main_speeches.items():
                # 将内容按行分割
                lines = [line.strip() for line in content.split('\n') if line.strip()]
                
                # 检查话术内容是否在文件中
                if speech_content in lines:
                    return file_name
            
            return None
        except Exception as e:
            self.logger.error(f"获取话术文件名失败: {str(e)}")
            return None
    
    def reload(self) -> None:
        """
        重新加载主话术
        """
        self.logger.info("重新加载主话术")
        self._load_main_speeches()
    
    def get_all_speech_files(self):
        """
        获取所有主话术文件
        
        @return: 主话术文件字典，key为文件名，value为文件内容
        """
        if not self._main_speeches:
            self.reload()
            
        # 添加调试日志
        self.logger.info(f"获取所有主话术文件，共 {len(self._main_speeches)} 个文件")
        
        # 使用与_load_main_speeches相同的排序逻辑，同时支持xx-xxx.txt和x.y.txt格式
        def get_sort_key(filename):
            """
            从文件名中提取排序键
            支持以下格式：
            1. 破折号格式：01-产品名称.txt
            2. 纯数字格式：1.0.txt
            3. 带花括号的格式：3.0{停顿}.txt
            4. 带后缀的格式：6.1人数时间.txt
            """
            try:
                # 先尝试破折号格式（如01-产品名称.txt）
                import re
                dash_match = re.match(r'^(\d+)-', filename)
                if dash_match:
                    sort_key = int(dash_match.group(1))
                    self.logger.debug(f"文件'{filename}'使用破折号格式排序键: {sort_key}")
                    return sort_key
                
                # 尝试x.y格式（如1.0.txt, 3.0{停顿}.txt）
                dot_match = re.match(r'^(\d+\.\d+)', filename)
                if dot_match:
                    sort_key = float(dot_match.group(1))
                    self.logger.debug(f"文件'{filename}'使用浮点数格式排序键: {sort_key}")
                    return sort_key
                
                # 尝试纯数字格式（如1.txt, 2.txt）
                num_match = re.match(r'^(\d+)\.', filename)
                if num_match:
                    sort_key = int(num_match.group(1))
                    self.logger.debug(f"文件'{filename}'使用整数格式排序键: {sort_key}")
                    return sort_key
            except (ValueError, IndexError, AttributeError) as e:
                self.logger.warning(f"解析文件名'{filename}'的排序键时出错: {str(e)}")
                
            # 如果无法提取排序键，则返回一个很大的数，使其排在最后
            self.logger.debug(f"文件'{filename}'无法提取排序键，将排在最后")
            return float('inf')
        
        # 按照自定义排序键排序文件名
        result = {}
        file_names = sorted(self._main_speeches.keys(), key=get_sort_key)
        
        # 添加调试日志
        self.logger.info(f"排序前的文件名列表: {list(self._main_speeches.keys())}")
        self.logger.info(f"排序后的文件名列表: {file_names}")
        
        # 构建结果字典
        for file_name in file_names:
            result[file_name] = self._main_speeches[file_name]
            
        return result 